package com.twb.core.security.service.impl;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.twb.core.base.entity.BaseLoginUser;
import com.twb.core.cache.redis.RedisUtil;
import com.twb.core.config.TwbConfigProperties;
import com.twb.core.constants.TwbConstants;
import com.twb.core.exception.TokenException;
import com.twb.core.security.jwt.JwtUtil;
import com.twb.core.security.jwt.Subject;
import com.twb.core.security.service.ITokenService;
import com.twb.core.util.EncryptUtil;

@Service("twbJwtJedisTokenService")
public class TwbJwtJedisTokenService implements ITokenService {

	@Autowired
	private RedisUtil redisUtil;
	@Autowired
	private TwbConfigProperties twbConfigProperties;
	
	@Override
	public <T extends BaseLoginUser> String createToken(T t,Subject subject,String appId,String appToken,String appSecret) throws Exception {
		// TODO Auto-generated method stub
		if (null == subject || subject.getExp() == 0) {
			subject = new Subject();
			subject.setExp(3600L);
		}
		String jwtSubject = JwtUtil.generalSubject(subject);
		String userSub = null;
		if(subject.getUid() != null) {
			userSub = EncryptUtil.getInstance().SHA1(subject.getUid())+".";
			//如果开启单用户模式，登录时会删除掉该用户原来的token
			Boolean singleUser = twbConfigProperties.getSingleUser();
			if(singleUser) {
				redisUtil.deleteByPrex(twbConfigProperties.getLoginRedisKey(userSub)+"*");
			}
		}
		//系统加密私钥
		String authSecret = twbConfigProperties.getAuthSecret();
		if(StringUtils.isBlank(authSecret)) {
			authSecret= TwbConstants.AUTH_SECRET;
		}
		String token = userSub+JwtUtil.createJWT(appId, jwtSubject, 10,appToken,authSecret+appSecret);//生成的token永不过期
		String key = twbConfigProperties.getLoginRedisKey(token);
		t.setToken(token);
		redisUtil.set(key, t,subject.getExp(),TimeUnit.SECONDS);
		return token;
	}

	@Override
	public boolean checkToken(String jwtToken,String appToken,String appSecret){
		//解析token验证是否有效。
		if(null == jwtToken){
			return false;
		}
		try {
			boolean checked = false;
			String key = twbConfigProperties.getLoginRedisKey(jwtToken);
//			JwtUtil.parseJWT(jwtToken,appToken,appSecret);暂时关掉jwt的验证，貌似用法不对
			boolean hasToken = redisUtil.containsKey(key);
			if(hasToken){//判断在redis中是否存在该token，如果不存在，说明已经失效。
				//如果token有效，则更新token有效时间
				checked = true;
			}else{
				checked = false;
			}
			
			return checked;
		} catch (Exception e) {
			// TODO: handle exception
			return false;
		}
	}

	@Async
	@Override
	public Boolean refreshToken(String jwtToken, Long timeoutSeconds) throws Exception {
		boolean refresh = false;
		String key = twbConfigProperties.getLoginRedisKey(jwtToken);
		boolean hasToken = redisUtil.containsKey(key);
		if(hasToken){//判断在redis中是否存在该token，如果不存在，说明已经失效。
			//如果token有效，则更新token有效时间
			Collection<String> keys = redisUtil.keys("*"+jwtToken);
			for (String k : keys) {
				redisUtil.expire(k,timeoutSeconds,TimeUnit.SECONDS);
			}
			refresh = true;
		}else{
			refresh = false;
		}
		return refresh;
	}
	@Override
	public <T extends BaseLoginUser> T getLoginUser(String token) {
		if (StringUtils.isEmpty(token)) {
			return null;
		}
		String key = twbConfigProperties.getLoginRedisKey(token);
		T newInstance = redisUtil.get(key);
		return newInstance;
	}
	@Override
	public boolean removeLoginUser(String token) {
//		String key = twbConfigProperties.getLoginRedisKey(token);
		try {
			//把所有用户相关的缓存数据全部删除
			Collection<String> keys = redisUtil.keys("*"+token);
			redisUtil.delete(keys);
			return true;
		} catch (Exception e) {
			throw new TokenException("会话删除失败");
		}
	}

	@Override
	public <T extends BaseLoginUser> boolean refreshLoginUser(T user, String token,Subject subject) {
		try {
			if (null == subject || subject.getExp() == 0) {
				subject = new Subject();
				subject.setExp(3600L);
			}
			String key = twbConfigProperties.getLoginRedisKey(token);
			redisUtil.set(key, user,subject.getExp(),TimeUnit.SECONDS);
			return true;
		} catch (Exception e) {
			throw new TokenException("会话刷新失败");
		}
	}

	@Override
	public Set<String> getLoginUserDataScopeCache(String token) {
		String key = twbConfigProperties.getLoginDataScopeRedisKey(token);
		return redisUtil.get(key);
	}
	
	@Override
	public List<BaseLoginUser> searchOnlineLoginUser(int pageNum,int pageSize) {
		String key = twbConfigProperties.getCachePrefix()+":login*";
		Set<String> keys = redisUtil.scan(key, pageNum, pageSize);
		List<BaseLoginUser> list = redisUtil.mget(keys);
		return list;
	}

	@Override
	public Long countOnlineLoginUser() {
		String key = twbConfigProperties.getCachePrefix()+":login*";
		long count = redisUtil.size(key);
		return count;
	}
	@Override
	public <T extends BaseLoginUser> T getTwbLoginUser(String token) {
		String key = this.twbConfigProperties.getTwbLoginRedisKey(token);
		return redisUtil.get(key);
	}

	@Override
	public boolean lockLoginUser(String loginName, long timeout, int maxCount) {
		String key = twbConfigProperties.getCachePrefix()+":lockUsers:"+loginName;
		Integer count = redisUtil.get(key);
		if(count != null) {
			if(count >= maxCount) {
				return true;
			}
			count++ ;
		}else {
			count = 1;
		}
		redisUtil.set(key, count, timeout, TimeUnit.MINUTES);
		return false;
	}

	@Override
	public boolean unlockLoginUser(String loginName) {
		String key = twbConfigProperties.getCachePrefix()+":lockUsers:"+loginName;
		boolean containsKey = redisUtil.containsKey(key);
		if(containsKey) {
			redisUtil.delete(key);
		}
		return true;
	}

	@Override
	public boolean checklockLoginUser(String loginName, int maxCount) {
		String key = twbConfigProperties.getCachePrefix()+":lockUsers:"+loginName;
		boolean containsKey = redisUtil.containsKey(key);
		if(containsKey) {
			int count = redisUtil.get(key);
			if(count >= maxCount) {
				return true;
			}
		}
		return false;
	}
}
